#include "http_server.h"
#include "io_config.h"
#include "api_map.h"
#include "esp_sleep.h"
#include "driver/rtc_io.h"
#include "esp_log.h"

#define TAG "api.sleep"
#define log_e(...) ESP_LOGE(TAG, __VA_ARGS__)
#define log_i(...) ESP_LOGI(TAG, __VA_ARGS__)
#define log_w(...) ESP_LOGW(TAG, __VA_ARGS__)

#if API_ENABLE_CONFIG_IO
static uint16_t wakeup(http_server_t server, httpd_ws_frame_t *frame, void *data)
{
    if (data) /* set */
    {
        return 0;
    }
    else /* get */
    {
        char *str = (char *)server->data;
        uint16_t source_len = strlen(str);
        uint16_t len = source_len;
        len += sprintf(&str[len], "\"wakeup\":[{");
        len += sprintf(&str[len], "\"enable\":%s,", 1 ? "true" : "false");
        len += sprintf(&str[len], "\"timer\":%d,", 0); /* 定时唤醒 */
        len += sprintf(&str[len], "\"gpio\":[%d]", 0);
        len += sprintf(&str[len], "}],");
        return len - source_len;
    }
}
#endif

static void call_sleep(http_server_t server, httpd_ws_frame_t *frame, void *data)
{
    esp_sleep_disable_wakeup_source(ESP_SLEEP_WAKEUP_ALL);
    uint8_t have_wakeup_source = 0;
#if API_ENABLE_CONFIG_IO
#if SOC_PM_SUPPORT_EXT_WAKEUP
#if SOC_PM_SUPPORT_EXT1_WAKEUP
    int io_num = 0;
    int level = 0;
    if (rtc_gpio_is_valid_gpio(io_num))
    {
        ESP_ERROR_CHECK(esp_sleep_enable_ext1_wakeup(1ULL << io_num, level));
        have_wakeup_source = 1;
    }
    else
        log_e("GPIO %d is not an RTC IO", io_num);
#endif /* SOC_PM_SUPPORT_EXT1_WAKEUP */
#endif // SOC_PM_SUPPORT_EXT_WAKEUP
#endif /* API_ENABLE_CONFIG_IO */

#if CONFIG_IDF_TARGET_ESP32
    rtc_gpio_isolate(GPIO_NUM_12);
#endif // CONFIG_IDF_TARGET_ESP32

    log_i("Start Deep sleep");
    if (!have_wakeup_source)
    {
        uint64_t timeout = 1 * 60 * 60 * 1000000ll; /* 1hour */
        log_i("Enabling timer wakeup, timeout=%llus", timeout / 1000000);
        ESP_ERROR_CHECK(esp_sleep_enable_timer_wakeup(timeout));
    }
    esp_deep_sleep_start();
}

static void sleep_init(void)
{
#if API_ENABLE_CONFIG_IO
    io_config_add(wakeup);
#endif
    ADD_API_ITEM_ALIAS("deep_sleep", call_sleep);
}
ADD_API(sleep_init)
